﻿#define TEST

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Collections;
using System.Runtime.InteropServices;

using SuperMapLib;

namespace JR_RouteAlarm
{
    public partial class Form1 : Form
    {
        private Utility utl = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = openFileDialog1.FileName;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox2.Text = saveFileDialog1.FileName;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            button3.Enabled = false;
            button4.Enabled = true;

            Initialize();
            MakeBuffer();
            utl.ReleaseMemory();

            button3.Enabled = true;
            button4.Enabled = false;
        }

        private void Initialize()
        {
            Utility.datasourceAlias = "route"; //textBox1.Text.Substring(textBox1.Text.IndexOf(".sdb"));
            utl = new Utility(axSuperWorkspace1, textBox1.Text);
        }

        private void MakeBuffer()
        {
            soDataset objDS = null;
            soStrings objFieldStr = null;

            objFieldStr = new soStrings();
            objFieldStr.Add(Route.FEATURE_CD);
            objFieldStr.Add(Route.DAIBUN_CD);
            objFieldStr.Add(Route.TSUUSHO_CD);

            for (int i = 1; i <= utl.objSource.Datasets.Count; i++)
            {
                objDS = utl.objSource.Datasets[i];
                if (!objDS.Name.Contains(Utility.BUFFER_TITLE))
                {
                    MakeRoute(objDS as soDatasetVector, objFieldStr);
                    //MakeBufferExe(objDS.Name);
                    foreach (object key in Route.routePartsPair.Keys)
                    {
                        foreach (object obj in Route.routePartsPair[key] as ArrayList)
                        {
                            Buffering((soGeoLine)obj);
                        }
                    }

                    BuildBuffer(objDS.Name + Utility.BUFFER_TITLE);
                }
            }

            Marshal.ReleaseComObject(objFieldStr);
            objFieldStr = null;
            Marshal.ReleaseComObject(objDS);
            objDS = null;
        }

        private void MakeRoute(soDatasetVector objDSV, soStrings objFieldStr)
        {
            soRecordset objRS = null;

            objRS = objDSV.Query("-1 < 0", false, objFieldStr, 
                "group by " + Route.FEATURE_CD + ", " + Route.DAIBUN_CD + ", " + Route.TSUUSHO_CD);

            if (objRS != null && !(objRS.IsBOF() && objRS.IsEOF()))
            {
                if (!objRS.IsBOF())
                {
                    objRS.MoveFirst();
                }
                IRoute route = new Route();
#if TEST
                for (int j = 0; j < objRS.RecordCount / 100; objRS.MoveNext(), j++)
#else
                for (; !objRS.IsEOF(); objRS.MoveNext())
#endif
                {
                    route.MakePartsForRoute(objDSV, objRS);
                }

                Marshal.ReleaseComObject(objRS);
                objRS = null;
            }
        }

        private void MakeBufferExe(string dsName)
        {
            foreach (object key in Route.routePartsPair.Keys)
            {
                foreach (object obj in Route.routePartsPair[key] as ArrayList)
                {
                    Buffering((soGeoLine)obj);
                }
            }

            BuildBuffer(dsName + Utility.BUFFER_TITLE);
        }

        private void Buffering(soGeoLine objLine)
        {
            soGeoRegion objRegion = null;
            soGeoLine objLineTmp = null;
            soGeoLine[] objSideLines = new soGeoLine[Utility.MAX_ROUTE_PART_COUNT];
            soGeoPoint objPoint = null;
            soGeoPoint[] objTerminalPoints = new soGeoPoint[2];
            soPoints tmpPoints = null;
            soPoints validPoints = null;
            //double radiusLen = 0D;
            double lineLen = 0D;
            int linePartsCount = 0;
            

            objRegion = objLine.Buffer(Utility.BUFFER_ALARM_DISTANCE, Utility.BUFFER_ALARM_SMOOTH);
            objLineTmp = objRegion.ConvertToLine();
            tmpPoints = objLineTmp.GetPartAt(1);
            //objPoint = new soGeoPoint();
            //objPoint.x = tmpPoints[1].x;
            //objPoint.y = tmpPoints[1].y;
            //radiusLen = objPoint.DistanceTo(objLine as soGeometry);
            lineLen = objLine.Length;
            objTerminalPoints[0] = new soGeoPoint();
            objTerminalPoints[1] = new soGeoPoint();
            objTerminalPoints[0].x = objLine.FindPointOnLineByDistance(0).x;
            objTerminalPoints[0].y = objLine.FindPointOnLineByDistance(0).y;
            objTerminalPoints[1].x = objLine.FindPointOnLineByDistance(lineLen).x;
            objTerminalPoints[1].y = objLine.FindPointOnLineByDistance(lineLen).y;
            linePartsCount = tmpPoints.Count;
            validPoints = new soPoints();
            objPoint = new soGeoPoint();
            //for (int i = 1, delCount = 0; i < linePartsCount - delCount; i++)
            for (int i = 1; i < linePartsCount; i++)
            { 
                objPoint.x = tmpPoints[i].x;
                objPoint.y = tmpPoints[i].y;
                //if (Math.Round(objPoint.DistanceTo(objTerminalPoints[0] as soGeometry), Utility.PRECISION) 
                //    == Math.Round(Utility.BUFFER_ALARM_DISTANCE, Utility.PRECISION)
                //    || Math.Round(objPoint.DistanceTo(objTerminalPoints[1] as soGeometry), Utility.PRECISION) 
                //    == Math.Round(Utility.BUFFER_ALARM_DISTANCE, Utility.PRECISION))
                if (Math.Abs(objPoint.DistanceTo(objTerminalPoints[0] as soGeometry) 
                        - Utility.BUFFER_ALARM_DISTANCE) < Utility.PRECISION
                    || Math.Abs(objPoint.DistanceTo(objTerminalPoints[1] as soGeometry) 
                        - Utility.BUFFER_ALARM_DISTANCE) < Utility.PRECISION)
                {
                    //delCount++;
                    //tmpPoints.Remove(i, 1);
                    validPoints.Add(tmpPoints[i]);
                }
            }
            for (int i = 1; i < validPoints.Count; i++)
            {
                objSideLines[i - 1] = new soGeoLine();
                objSideLines[i] = new soGeoLine();

                if (objLineTmp.Split(validPoints[i], objSideLines[i - 1], objSideLines[i]))
                {
                    objLineTmp = objSideLines[i];
                }
                //if (objLineTmp.GetPartAt(1).Count == 2)
                //{
                //    break;
                //}
            }

            objLineTmp.SetEmpty();
            tmpPoints.RemoveAll();
            //for (int i = 1; i < objSideLines.Length; i++)
            for (int i = 1; i < validPoints.Count; i++)
            {
                //if (objSideLines[i] == null)
                //{
                //    break;
                //}
                //if (Math.Round(objSideLines[i].DistanceTo(objLine as soGeometry), Utility.PRECISION) 
                //        == Math.Round(Utility.BUFFER_ALARM_DISTANCE, Utility.PRECISION))
                //if (Math.Truncate(objSideLines[i].Length) 
                //    == Math.Truncate(lineLen))
                if (Math.Abs(objSideLines[i].Length - lineLen) < Utility.PRECISION)
                {
                    tmpPoints.Add(objSideLines[i].FindPointOnLineByDistance(0));
                    tmpPoints.Add(objSideLines[i].FindPointOnLineByDistance(lineLen));
                }
                if (tmpPoints.Count == 4)
                {
                    tmpPoints.Add(tmpPoints[1]);
                    break;
                }
            }

            objLineTmp.AddPart(tmpPoints);

            Utility.routeLnWithRgn[objLine] = objLineTmp.ConvertToRegion();

            Marshal.ReleaseComObject(objRegion);
            objRegion = null;
            Marshal.ReleaseComObject(objLineTmp);
            objLineTmp = null;
            Marshal.ReleaseComObject(tmpPoints);
            tmpPoints = null;
        }

        private void BuildBuffer(string datasetName)
        {
            soDatasetVector objDatasetV = null;
            soRecordset objRecords = null;
            soGeoLine objLine = null;

            if (!utl.objSource.IsAvailableDatasetName(datasetName))
            {
                utl.objSource.DeleteDataset(datasetName);
            }
            objDatasetV = (soDatasetVector)utl.objSource.CreateDataset(
                datasetName, seDatasetType.scdRegion, seDatasetOption.scoDefault, null);
            objRecords = objDatasetV.Query("-1 < 0", true, null, "");

            int i = 0, j = 0;
            foreach (object key in Route.routePartsPair.Keys)
            {
                foreach (object obj in Route.routePartsPair[key] as ArrayList)
                {
                    objLine = (soGeoLine)obj;
                    i = objRecords.AddNew(Utility.routeLnWithRgn[objLine] as soGeometry, false);
                    Console.WriteLine("{0}, {1}", ++j, i);
                    objRecords.Update();
                }
            }

            Marshal.ReleaseComObject(objRecords);
            objRecords = null;
            Marshal.ReleaseComObject(objDatasetV);
            objDatasetV = null;
        }
    }
}